#ifndef __sgNode__h__included__
#define __sgNode__h__included__

#include "neiderra/core/Base.h"

#include "Mesh.h"
#include "Image.h"

#include "neiderra/math/Vectors.h"
#include "neiderra/math/Quaternion.h"
#include "Texture.h"
#include "Alphabet.h"

//#include "aScene.h"

// #include "aSceneObject.h"

using namespace neiderra::math;
//using neiderra::scene::aScene;
// using neiderra::scene::aSceneObject;
using neiderra::core::iObject;
using neiderra::rendering::Texture;

#include <vector>

using std::vector;

namespace neiderra {
	namespace scene {
		class Scene; 
		class SceneObject;
	}
	using namespace scene;

    namespace rendering {

        class iRenderer;
		class ParticleSystem;
		class Particle;
		class TextString;

        namespace sg {

			// TODO SG Factory
			class sgNode: public iObject
			{
            public:
//  				sgNode(Scene*);
				sgNode() ;
                virtual ~sgNode();
                virtual void addNode(sgNode*);
				virtual void setParent(sgNode*);
// 				virtual void SetScene(Scene* scene);
//  				virtual void SetSceneObject(SceneObject*);
				virtual void SetDepthLevel(int depth) {_depthLevel = depth;}
				void setTraverseLevel(int x) {_traverseLevel = x; }
				inline int getTraverseLevel() { return _traverseLevel; }
				virtual sgNode* getParent() { return _parent; }
				virtual void removeNode(sgNode*);
// 				virtual Scene* GetScene();
// 				virtual SceneObject* GetSceneObject();
				virtual void traverse(iRenderer*);
				// HACK FindContainer() doesn't work with common nodes
				virtual sgNode* FindContainer(unsigned x, unsigned y);
				virtual int GetDepthLevel() { return _depthLevel; }
				static int maxTraverseLevel;
				static int currentPass;
				inline bool canPass();
            protected:
                vector<sgNode*> _children;
				sgNode* _parent;
// 				Scene* _scene;
// 				SceneObject* _sceneObject;
				int _depthLevel;
				int _traverseLevel;
			};

			class sgDOFNode: public sgNode
			{
            public:
// 				sgDOFNode(Scene*);
				sgDOFNode();
                virtual ~sgDOFNode();

                virtual void traverse(iRenderer*);
            public:
				math::vec3 v;
			};

			class sgParticleSystemNode: public sgNode
			{
			public:
				sgParticleSystemNode();
//                 sgParticleSystemNode(Scene*);
				virtual void traverse(iRenderer*);
				ParticleSystem* _particleSystem;
			};

			class sgDOFRotateNode: public sgDOFNode
			{
            public:
// 				sgDOFRotateNode(Scene*);
				sgDOFRotateNode();
                virtual ~sgDOFRotateNode();

                virtual void traverse(iRenderer*);

                //! angle - the rotation angle; x, y, z - vector coordinates
                virtual void rotate(float angle, float x, float y, float z);

				virtual void rotate(quat&);

            public:
                float _angle, _x, _y, _z;
				quat _rotation;
			};

			class sgDOFTranslateNode: public sgDOFNode
			{
            public:
// 				sgDOFTranslateNode(Scene*);
				sgDOFTranslateNode();
                virtual ~sgDOFTranslateNode();

                virtual void traverse(iRenderer*);

                virtual void translate(vec3&);

            public:
                vec3 _trans;
			};

			class sgDOFScaleNode: public sgDOFNode
			{
            public:
				sgDOFScaleNode();
//                 sgDOFScaleNode(Scene*);
                virtual ~sgDOFScaleNode();

                virtual void traverse(iRenderer*);

                //! x, y, z - scale factors for x-, y-, z-axes
                virtual void scale(float x, float y, float z);

            private:
                float _x, _y, _z;
			};

			class sgDOFTripleNode: public sgDOFTranslateNode 
			{
			public:
				sgDOFTripleNode();
				virtual ~sgDOFTripleNode();

				sgDOFRotateNode* getRotateNode() { return _rotateNode; }
				sgDOFScaleNode* getScaleNode() { return _scaleNode; }

				virtual void addNode(sgNode*);

			protected:
				sgDOFRotateNode* _rotateNode;
				sgDOFScaleNode* _scaleNode;
			};

			class sgDOFOrientNode: public sgDOFNode
			{
			public:
				sgDOFOrientNode();
				sgDOFOrientNode(Scene*);

				virtual ~sgDOFOrientNode(){}

				virtual void traverse(iRenderer*);

				virtual void setOrientation(vec3& pos, vec3& view, vec3& up)
				{
					_pos = pos;
					_view = view;
					_up = up;
				}
			protected:
				vec3 _pos, _view, _up;
			};

			//! Dot node represents something at the point(x,y,z)
			class sgDotNode: public sgNode
			{
			public: 
 				sgDotNode(): sgNode() {}
// 				sgDotNode(Scene*): sgNode() {_x = _y = _z = 0;}
				virtual ~sgDotNode() {}

				virtual void setPosition(float x, float y, float z) 
				{_x = x; _y = y; _z = z;}

				virtual void getPosition(vec3& v)
				{v.x = _x; v.y = _y; v.z = _z;}
				virtual float getX(){return _x;}
				virtual float getY(){return _y;}
				virtual float getZ(){return _z;}

			protected:
				float _x,_y,_z;
			};

			class sgGeometryNode: public sgDotNode
			{
            public:
				sgGeometryNode();
//                 sgGeometryNode(Scene*);
                virtual ~sgGeometryNode();

                virtual void traverse(iRenderer*);

                //! assign mesh to this node
                virtual void setMesh(Mesh*);
                //! obtain mesh assigned to this node
                virtual Mesh* getMesh();

				virtual void setTexture(Texture*);
                virtual Texture* getTexture();
				void useLocalTransform(bool f) { _useLocalTransform = f; }

            private:
				bool _useLocalTransform;
                Mesh* _mesh;
				Texture* _texture;
			};
			
			class sgImageNode: public sgNode
			{
            public:
// 				sgImageNode(): sgNode(0) { _depthLevel =0; }
//                 sgImageNode(Scene*);
                virtual ~sgImageNode();

                virtual void traverse(iRenderer*);

                //! assign image to this node
                virtual void setImage(Image*);
                //! obtain image from this node
                virtual Image* getImage();

                //! set rendering position
                virtual void setXY(int x, int y);

				virtual sgNode* FindContainer(unsigned x, unsigned y);

            private:
                Image* _image;

			protected:
                int _x, _y;
			};
			
			class sgTextNode: public sgImageNode
			{
				public:
					sgTextNode(): sgImageNode() {_str = 0;}
// 					sgTextNode(Scene* scene): sgImageNode( scene ) {_str = 0;}
					virtual ~sgTextNode( ) {}
					
					virtual void traverse(iRenderer*);
					virtual void SetTextString(TextString* str, int px, int py) {_str = str; _pen_x = px; _pen_y = py;}
					virtual sgNode* FindContainer( unsigned x, unsigned y ) {return 0;}
					int GetPenX(){return _pen_x;}
					int GetPenY(){return _pen_y;}
				protected:
					TextString* _str;
					int _pen_x, _pen_y;
			};

			//class sgStringNode: public sgImageNode
			struct sg2dNode: public sgNode
			{
// 				sg2dNode(Scene* scene): sgNode(scene) {}
				unsigned _x, _y;
			};

			struct sgStringNode: public sg2dNode {
// 				sgStringNode(Scene* scene);
				virtual ~sgStringNode();
				virtual void traverse(iRenderer*);

				string _s;
				rendering::Alphabet* _alphabet;
			};

			class sgCameraNode: public sgDotNode
			{
			public:
				sgCameraNode(): sgDotNode() {}
// 				sgCameraNode(Scene*);
				virtual ~sgCameraNode();

				virtual void traverse(iRenderer*);

				//! get destination node
				virtual sgDotNode* getDestinationNode();

				//! set destination node
				virtual void setDestinationNode(sgDotNode*);

			protected:
				sgDotNode* _dest;
			};
        }
    }
}

#endif
